#pragma once
#include "Epoll.h"
#include <memory>
#include <unordered_map>
#include "connection.h"

using namespace Epoll_module;

// 制造Connection对象的工厂
class Connection_factor
{
public:
    static Connection *BuildListenConnection(int sockfd, uint32_t events,
                                             func_c recver,
                                             Epoll_server *epoller)
    {
        Connection *pcon = new Connection(sockfd, events, epoller);
        pcon->Fill_callback(recver, nullptr, nullptr);
        return pcon;
    }

    static Connection *BuildNormalConnection(int sockfd, uint32_t events,
                                             func_c recver, func_c sender, func_c excepter,
                                             Epoll_server *epoller)
    {
        Connection *pcon = new Connection(sockfd, events, epoller);
        pcon->Fill_callback(recver, sender, excepter);
        return pcon;
    }
};

// 用于管理(组织)所描述的各种对象Connection/Epoll
class Epoll_server
{
    const static int g_maxevents = 37;

public:
    Epoll_server() : _epoller(make_unique<Epoll>()), _timeout(-1) // 默认阻塞等待
    {
        // 初始化, 创建epoll模型
        _epoller->Epoll_Init();
    }

    void AddConnection(Connection *pcon)
    {
        int sockfd = pcon->Getfd();
        uint32_t events = pcon->Getevents();
        if (_connections.count(sockfd) != 0)
        {
            cout << "已经建立该文件描述符连接" << endl;
            return;
        }
        _connections[sockfd] = pcon;
        _epoller->Epoll_addevent(sockfd, events);
    }

    void ModReadWrite(int sockfd, bool readable, bool writeable)
    {
        uint32_t events = (readable ? EPOLLIN : 0) | (writeable ? EPOLLOUT : 0) | EPOLLET;

        // 如果没有变化就不必修改事件关心
        if (events == _connections[sockfd]->Getevents())
            return;

        // 1.修改用户态的连接管理事件
        _connections[sockfd]->SetEvents(events);

        // 2.修改内核态的epoll关心事件
        _epoller->Epoll_modevent(sockfd, events);
    }

    void CloseConnection(int sockfd)
    {
        // 1.取消关心
        _epoller->Del_event(sockfd);

        // 2.取消对该connection对象管理
        _connections.erase(sockfd);
    }

    void Run()
    {
        while (true)
        {
            int n = _epoller->Epoll_wait(_revents, g_maxevents, _timeout);
            // Epoll_wait将已经等待成功的事件放到_revents(就绪队列)里
            switch (n)
            {
            case 0:
                cout << "no file descriptor became ready during the requested timeout..." << endl;
                break;
            case -1:
                std::cerr << "epoll_wait error... " << strerror(errno) << std::endl;
                break;
            default:
                // cout << "event preparation..." << endl;
                Handler_event(n);
                break;
            }
        }
    }

    ~Epoll_server()
    {
    }

private:
    int _timeout;
    unique_ptr<Epoll> _epoller;
    epoll_event _revents[g_maxevents];
    unordered_map<int, Connection *> _connections; // 对所有的连接进行管理（组织）

private:
    void Handler_event(int n) // 事件派发(执行回调方法)
    {
        for (int i = 0; i < n; i++)
        {
            int sockfd = _revents[i].data.fd;
            uint32_t events = _revents[i].events;
            Connection *cur = _connections[sockfd]; // 拿到对应文件描述符的Connection连接

            if ((events & EPOLLIN) && _connections.count(sockfd)) // 读事件就绪
            {
                cur->_recver(cur); // 执行回调函数
            }
            if ((events & EPOLLOUT) && _connections.count(sockfd)) // 写事件就绪
            {
                cur->_sender(cur); // 执行回调函数
            }
            if (events & EPOLLHUP || events & EPOLLERR) // 异常事件就绪
            {
                cur->_excepter(cur); // 执行回调函数
            }
        }
    }
};